/**
  ******************************************************************************
  * @file    uart_handler.c
  * @author  ashuai0110
  * @version V2.4
  * @date    2024-09-10
  * @brief   串口管理(使用帧间隔分帧或现有的分帧方法)
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  * Change Logs:
  * Date          Author        Notes
  * 2023-10-27    ashuai0110    完成基本内容
  * 2023-12-29    ashuai0110    修改从组件计时节拍接口获取时基,修改使用ring_buffer组件
  * 2024-03-03    ashuai0110    修改帧间隔时间为用户自定义参数
  * 2024-09-01    ashuai0110    修改超时判断逻辑,删除一些assert
  * 2024-09-10    ashuai0110    修改数组为对象形式
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "uart_handler.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup uart_handler uart_handler
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup uart_handler_global_functions uart handler global functions
 * @{
 */

/**
  * @brief  串口管理初始化
  *
  * @param  _uartHr   : 串口管理实例
  *
  * @param  txBuf     : 串口发送缓冲区
  *
  * @param  txLen     : 串口发送缓冲区大小
  *
  * @param  rxBuf     : 串口接收缓冲区
  *
  * @param  rxLen     : 串口接收缓冲区大小
  *
  * @param  txEnFn    : 串口发送前准备函数
  *
  * @param  frameIntv : 帧间隔超时时间ms,不关心可填0
  *
  * @param  timeout   : 接收超时时间ms,不关心可填0
  *
  * @retval None
  */
void uart_hr_init(uart_handler_t *_uartHr, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint32_t frameIntv, uint32_t timeout)
{
    MW_ASSERT_PARAM(IS_VALID_POINTER(_uartHr));
    MW_ASSERT_PARAM(IS_VALID_POINTER(txBuf));
    MW_ASSERT_PARAM(IS_VALID_POINTER(rxBuf));
    MW_ASSERT_PARAM(IS_VALID_POINTER(txEnFn));
    
    /* 初始化各参数 */
    memset(_uartHr, 0, sizeof(uart_handler_t));
    /* 收发的环形缓冲区初始化 */
    ring_buffer_init(&_uartHr->txRingBuffer, txBuf, txLen);
    ring_buffer_init(&_uartHr->rxRingBuffer, rxBuf, rxLen);
    _uartHr->uartTxEnFn = txEnFn;
    _uartHr->targetFrameIntv = frameIntv;
    _uartHr->recTimeout = timeout;
}

/**
  * @brief  串口管理轮询处理
  *
  * @note   用户若不关心帧间隔和接收超时,此函数可忽略
  *
  * @param  _uartHr        : 串口管理实例
  *
  * @retval 返回轮询状态
  *    @arg MW_RET_OK      : 接收完成
  *    @arg MW_RET_ERR     : 接收未完成
  *    @arg MW_RET_TIMEOUT : 接收超时(无需求可忽略)
  */
uint8_t uart_hr_poll(uart_handler_t *_uartHr)
{
    uint32_t tickTmp;
    
    tickTmp = _uartHr->curFrameIntv;
    /* 帧间隔判断 */
    if(tickTmp && (mw_tick_get() - tickTmp) > _uartHr->targetFrameIntv)
    {
        /* 置零帧间隔计数 */
        _uartHr->curFrameIntv = 0;
        
        return MW_RET_OK;
    }
    tickTmp = _uartHr->recTimeoutCnt;
    /* 接收超时判断 */
    if(tickTmp && (mw_tick_get() - tickTmp) > _uartHr->recTimeout)
    {
        _uartHr->recTimeoutCnt = 0; /* 置零接收超时 */
        
        return MW_RET_TIMEOUT;
    }
    
    return MW_RET_ERR;
}

/**
  * @brief  读出数据从串口接收缓冲区
  *
  * @param  _uartHr : 串口管理实例
  *
  * @param  pBuf    : 数据存储区
  *
  * @param  len     : 读出长度byte
  *
  * @retval 返回实际读出的长度
  */
uint32_t uart_hr_read_rx_buf(uart_handler_t *_uartHr, void *pBuf, uint32_t len)
{
    /* 从环形缓冲区读出数据 */
    len = ring_buffer_read(&_uartHr->rxRingBuffer, pBuf, len);
    
    return len;
}

/**
  * @brief  写入数据到串口接收缓冲区
  *
  * @note   一般加入到串口接收中断
  *
  * @param  _uartHr : 串口管理实例
  *
  * @param  pBuf    : 数据缓存区
  *
  * @param  len     : 写入长度byte
  *
  * @retval 返回实际写入的长度
  */
uint32_t uart_hr_write_rx_buf(uart_handler_t *_uartHr, void *pBuf, uint32_t len)
{
    /* 向环形缓冲区写入数据 */
    len = ring_buffer_write(&_uartHr->rxRingBuffer, pBuf, len);
    /* 若实际写入长度不为0则开启帧间隔计数 */
    if(0 < len)
    {
        _uartHr->curFrameIntv = mw_tick_get(); /* 开启帧间隔超时计数 */
        _uartHr->recTimeoutCnt = 0; /* 关闭接收超时计数 */
    }
    
    return len;
}

/**
  * @brief  读出数据从串口发送缓冲区
  *
  * @note   一般加入到串口发送中断
  *
  * @param  _uartHr : 串口管理实例
  *
  * @param  pBuf    : 数据存储区
  *
  * @param  len     : 读出长度byte
  *
  * @retval 返回实际读出的长度
  */
uint32_t uart_hr_read_tx_buf(uart_handler_t *_uartHr, void *pBuf, uint32_t len)
{
    /* 从环形缓冲区读出数据 */
    len = ring_buffer_read(&_uartHr->txRingBuffer, pBuf, len);;
    /* 若实际读出长度为0则关闭发送并开启接收超时计数 */
    if(0 == len)
    {
        _uartHr->uartTxEnFn(0);
        _uartHr->recTimeoutCnt = mw_tick_get();
    }
    
    return len;
}

/**
  * @brief  写入数据到串口发送缓冲区
  *
  * @param  _uartHr : 串口管理实例
  *
  * @param  pBuf    : 数据缓存区
  *
  * @param  len     : 写入长度byte
  *
  * @retval 返回实际写入的长度
  */
uint32_t uart_hr_write_tx_buf(uart_handler_t *_uartHr, void *pBuf, uint32_t len)
{
    /* 向环形缓冲区写入数据 */
    len = ring_buffer_write(&_uartHr->txRingBuffer, pBuf, len);
    /* 若实际写入长度不为0则开启发送 */
    if(len) { _uartHr->uartTxEnFn(1); }
    
    return len;
}

/**
  * @brief  设置串口管理帧间隔超时时间ms
  *
  * @param  _uartHr   : 串口管理实例
  *
  * @param  frameIntv : 帧间隔超时时间ms
  *
  * @retval None
  */
void uart_hr_set_frame_intv(uart_handler_t *_uartHr, uint32_t frameIntv)
{
    _uartHr->targetFrameIntv = frameIntv;
}

/**
  * @brief  获取串口管理帧间隔超时时间ms
  *
  * @param  _uartHr : 串口管理实例
  *
  * @retval 返回帧间隔超时时间ms
  */
uint32_t uart_hr_get_frame_intv(uart_handler_t *_uartHr)
{
    return _uartHr->targetFrameIntv;
}

/**
  * @brief  设置串口管理接收超时时间ms
  *
  * @param  _uartHr : 串口管理实例
  *
  * @param  timeout : 接收超时时间ms
  *
  * @retval None
  */
void uart_hr_set_rec_timeout(uart_handler_t *_uartHr, uint32_t timeout)
{
    _uartHr->recTimeout = timeout;
}

/**
  * @brief  获取串口管理接收超时时间ms
  *
  * @param  _uartHr : 串口管理实例
  *
  * @retval 返回串口管理接收超时时间ms
  */
uint32_t uart_hr_get_rec_timeout(uart_handler_t *_uartHr)
{
    return _uartHr->recTimeout;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
